/*
Copyright 2000-2011 Francois de Bertrand de Beuvron

This file is part of CoursBeuvron.

CoursBeuvron is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

CoursBeuvron is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with CoursBeuvron.  If not, see <http://www.gnu.org/licenses/>.
 */
package fr.insa.beuvron.tps.m2.dessin2DV3;

import fr.insa.beuvron.tps.m2.dessin2DV3.gui.FigurePanel;
import fr.insa.beuvron.tps.m2.dessin2DV3.gui.InterfacePartielle1;
import fr.insa.beuvron.tps.m2.dessin2DV3.gui.InterfacePartielle2;
import fr.insa.beuvron.tps.m2.dessin2DV3.gui.InterfacePartielle3;
import fr.insa.beuvron.tps.m2.dessin2DV3.gui.InterfacePartielle4;
import fr.insa.beuvron.tps.m3.gui.TestePanel;
import fr.insa.commun.Lire;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.util.ArrayList;

/**
 *
 * @author FdB
 */
public class EnsembleFigure implements Figure {

    /**
     * contient les figures de la scene
     */
    private ArrayList<Figure> lesFigs;

    public EnsembleFigure() {
        this.lesFigs = new ArrayList<Figure>();
    }

    public EnsembleFigure(ArrayList<Figure> init) {
        this.lesFigs = init;
    }

    @Override
    public String toString() {
        return "ensemble : " + this.nbrFigs() + " sous figures";
    }
    
    /**
     * permet de demander le type de la figure que l'utilisateur souhaite créer,
     * et appelle la méthode de création correspondante dans les sous-classes
     * de Figure.
     * @return la figure crée par l'utilisateur
     */
    public static Figure entreFigure() {
        char rep = 'u';
        Figure res = null;
        while (rep != 'P' && rep != 'S' && rep != 'T') {
            System.out.println("creation d'un Point, Segment ou Triangle (P ou S ou T) : ");
            rep = Lire.c();
            rep = Character.toUpperCase(rep);
            if (rep == 'P') {
                res = Point.demande();
            } else if (rep == 'S') {
                res = Segment.demande();
            } else if (rep == 'T') {
                res = Triangle.demande();
            } else {
                System.out.println("erreur : entrez la lettre P ou S");
            }
        }
        return res;
    }

    /**
     * Affiche un ensemble de figures contenues dans une liste
     * @return une description de toutes les figures
     */
    public void afficheListe() {
        System.out.println("----------- figures ----------------");
        for (int i = 0; i < this.getLesFigs().size(); i++) {
            System.out.println((i + 1) + " : " + this.getLesFigs().get(i));
        }
        System.out.println("------------------------------------");
    }

    /**
     * Affiche une description détaillée de l'ensemble des figures de la scene
     * @return une description de toutes les figures
     */
    public void afficheListeDetaillee() {
        System.out.println("----------- figures detail ---------");
        for (int i = 0; i < this.getLesFigs().size(); i++) {
            System.out.println((i + 1) + " : " + 
                    this.getLesFigs().get(i).jolieDescription(0));
        }
        System.out.println("------------------------------------");
    }

    /**
     * permet à l'utilisateur de choisir une figures parmis toutes les figures
     * définies dans la liste
     * @return le numéro de la case de la liste (0...nbrFigs-1) contenant la figure
     * choisie par l'utilisateur, ou -1 si l'utilisateur souhaite annuler 
     * la selection
     */
    public int choisiFigure(String message) {
        int rep = -1;
        while (rep < 0 || rep > this.getLesFigs().size()) {
            this.afficheListe();
            System.out.println(message);
            System.out.println("donnez un numéro de figure (0 : fin/annuler) : ");
            rep = Lire.i();
        }
        return rep - 1;
    }

    public ArrayList<Integer> choixMultiples() {
        ArrayList<Integer> res = new ArrayList<Integer>();
        int rep = 0;
        while (rep != -1) {
            String message = "choix multiple de figures\ndeja choisies : ";
            if (res.size() == 0) {
                message = message + "aucune";
            } else {
                for (int i = 0; i < res.size(); i++) {
                    message = message + (res.get(i)+1) + " ";
                }
            }
            rep = this.choisiFigure(message);
            if (rep != -1) {
                if (res.contains(rep)) {
                    System.out.println("figure " + (rep + 1) + " déjà sélectionnée");
                } else {
                    res.add(rep);
                }
            }
        }
        return res;
    }

    public void demandeSousEnsemble() {
        System.out.println("selectionnez les sous-figures");
        ArrayList<Integer> numFigs = this.choixMultiples();
        if (numFigs.size() == 0) {
            System.out.println("il faut au moins une sous-figure");
        } else {
            ArrayList<Figure> sousFigs = new ArrayList<Figure>();
            for (int i = 0; i < numFigs.size(); i++) {
                sousFigs.add(this.getLesFigs().get(numFigs.get(i)));
            }
            this.creeSousEnsemble(sousFigs);
        }
    }

    public void creeSousEnsemble(ArrayList<Figure> sousFigs) {
        // je supprime la selection de la scene
        this.getLesFigs().removeAll(sousFigs);
        // je cree une nouvelle EnsembleFigure
        EnsembleFigure nouvelle = new EnsembleFigure(sousFigs);
        // que j'ajoute dans la scene
        this.ajouteFigure(nouvelle);
    }

    public void demandeEclateEnsembleFigure() {
        int pos = this.choisiFigure("indiquez la figure composée à éclater");
        if (pos != -1) {
            if (this.getLesFigs().get(pos) instanceof EnsembleFigure) {
                EnsembleFigure groupe = (EnsembleFigure) this.getLesFigs().get(pos);
                this.eclateSousEnsemble(groupe);
            } else {
                System.out.println("la figure " + this.getLesFigs().get(pos) +
                        " n'est pas une EnsembleFigure");
            }
        }
    }
    

    public void eclateSousEnsemble(EnsembleFigure groupe) {
        this.getLesFigs().remove(groupe);
        for (int i = 0; i < groupe.nbrFigs(); i++) {
            this.ajouteFigure(groupe.getLesFigs().get(i));
        }
    }

    /**
     * supprime une figure spécifiée par sa position dans la lliste
     * @param numToDel numéro de case de la figure a supprimer
     */
    public void supprimeFigure(int numToDel) {
        if (numToDel >= this.getLesFigs().size()) {
            throw new Error("numéro de figure non définie : " + numToDel
                    + " (devrait être < " + this.getLesFigs().size() + ")");
        }
        this.getLesFigs().remove(numToDel);
    }

    /**
     * ajoute une figure dans la lliste.
     * Note : on aurait pu prévoir de créer une liste plus grand quand il
     * n'y a plus de place. Ici, on signale simplement une erreur
     */
    public void ajouteFigure(Figure fig) {
        this.getLesFigs().add(fig);
    }

    public int nbrFigs() {
        return this.getLesFigs().size();
    }
    
    public Figure getFig(int numFig) {
        return this.lesFigs.get(numFig);
    }

    public void afficheDistance() {
        System.out.println("calcul distance entre un point et une figure");
        System.out.println("entrez les coordonnées (px,py) du point : ");
        System.out.println("px = ");
        double px = Lire.d();
        System.out.println("py = ");
        double py = Lire.d();
        int fig1 = this.choisiFigure("choisissez la figure : ");
        if (fig1 != -1) {
            System.out.println("distance = " + this.getLesFigs().get(fig1).distance(new Point(px, py)));
        }
    }

    public void menu() {
        int rep = -1;
        while (rep != 0) {
            System.out.println("voulez vous : ");
            System.out.println("1) afficher toutes les figures");
            System.out.println("2) créer une nouvelle figure");
            System.out.println("3) supprimer une figure");
            System.out.println("4) afficher la distance entre une figure et un point");
            System.out.println("5) creer un groupe");
            System.out.println("6) eclater un groupe");
            System.out.println("7) debut interface graphique V1");
            System.out.println("8) debut interface graphique V2");
            System.out.println("9) debut interface graphique V3");
            System.out.println("10) debut interface graphique V4");
            System.out.println("11) dessiner la figure dans une zone graphique");
            System.out.println("");
            System.out.println("0) quitter");
            System.out.println("votre choix : ");
            rep = Lire.i();
            if (rep == 1) {
                this.afficheListeDetaillee();
            } else if (rep == 2) {
                this.ajouteFigure(entreFigure());
            } else if (rep == 3) {
                int num = this.choisiFigure("indiquez la figure à supprimer");
                if (num != -1) {
                    this.supprimeFigure(num);
                }
            } else if (rep == 4) {
                this.afficheDistance();
            } else if (rep == 5) {
                this.demandeSousEnsemble();
            } else if (rep == 6) {
                this.demandeEclateEnsembleFigure();
            } else if (rep == 7) {
                InterfacePartielle1 pan = new InterfacePartielle1(this);
                TestePanel.pack("Interface V1", pan);
           } else if (rep == 8) {
                InterfacePartielle2 pan = new InterfacePartielle2(this);
                TestePanel.tailleFixee("Interface V2", pan, 600, 600);
           } else if (rep == 9) {
                InterfacePartielle3 pan = new InterfacePartielle3(this);
                TestePanel.tailleFixee("Interface V3", pan, 600, 600);
           } else if (rep == 10) {
                InterfacePartielle4 pan = new InterfacePartielle4(this);
                TestePanel.tailleFixee("Interface V4", pan, 600, 600);
            } else if (rep == 11) {
                FigurePanel.affichageTest(this, 600, 600);
            }
        }
    }
    
    /**
     * cree des points et des segment aléatoires (dans le carre (0,0) - (echelle,echelle)
     * avec 3 chiffres significatifs.permet de faire des tests
     * @param nbr nombre de points/segments
     * @param echelle taille du carre contenant les figures
     * @param probaPoint proba de générer un point (1-probaPoint d'avoir un segment)
     */
    public void ajoutePointOuSegmentAlea(int nbr,double probaPoint,double echelle) {
        for (int i = 0 ; i < nbr ; i ++) {
            if (Math.random() < probaPoint) {
                Point p = new Point(Math.random()*echelle,Math.random()*echelle);
                this.ajouteFigure(p);
            } else {
                Point p1 = new Point(Math.random()*echelle,Math.random()*echelle);
                Point p2 = new Point(Math.random()*echelle,Math.random()*echelle);
                this.ajouteFigure(new Segment(p1, p2));
            }
        }
    }

    public static void main(String[] args) {
        EnsembleFigure scene = new EnsembleFigure();
//        scene.ajoutePointOuSegmentAlea(20, 0.5,1);
        scene.menu();
    }

    @Override
    /**
     * erreur si aucune sous figure
     */
    public double maxX() {
        if (this.getLesFigs().size() == 0) {
            throw new Error("maxX impossible sur un groupe de figures vide");
        }
        double res = this.getLesFigs().get(0).maxX();
        for (int i = 1; i < this.getLesFigs().size(); i++) {
            double curMax = this.getLesFigs().get(i).maxX();
            if (curMax > res) {
                res = curMax;
            }
        }
        return res;
    }

    @Override
    /**
     * erreur si aucune sous figure
     */
    public double minX() {
        if (this.getLesFigs().size() == 0) {
            throw new Error("minX impossible sur un groupe de figures vide");
        }
        double res = this.getLesFigs().get(0).minX();
        for (int i = 1; i < this.getLesFigs().size(); i++) {
            double curMin = this.getLesFigs().get(i).minX();
            if (curMin < res) {
                res = curMin;
            }
        }
        return res;
    }

    @Override
    /**
     * erreur si aucune sous figure
     */
    public double maxY() {
        if (this.getLesFigs().size() == 0) {
            throw new Error("maxY impossible sur un groupe de figures vide");
        }
        double res = this.getLesFigs().get(0).maxY();
        for (int i = 1; i < this.getLesFigs().size(); i++) {
            double curMax = this.getLesFigs().get(i).maxY();
            if (curMax > res) {
                res = curMax;
            }
        }
        return res;
    }

    @Override
    /**
     * erreur si aucune sous figure
     */
    public double minY() {
        if (this.getLesFigs().size() == 0) {
            throw new Error("minY impossible sur un groupe de figures vide");
        }
        double res = this.getLesFigs().get(0).minY();
        for (int i = 1; i < this.getLesFigs().size(); i++) {
            double curMin = this.getLesFigs().get(i).minY();
            if (curMin < res) {
                res = curMin;
            }
        }
        return res;
    }

    @Override
    /**
     * erreur si aucune sous figure
     */
    public double distance(Point p) {
        double res = this.getLesFigs().get(0).distance(p);
        for (int i = 1; i < this.getLesFigs().size(); i++) {
            double curMin = this.getLesFigs().get(i).distance(p);
            if (curMin < res) {
                res = curMin;
            }
        }
        return res;
    }

    @Override
    public String jolieDescription(int niveau) {
        String res = Utils.indent(this.toString() + "\n",niveau*2);
        for (int i = 0 ; i < this.getLesFigs().size() ; i ++) {
            res = res + this.getLesFigs().get(i).jolieDescription(niveau+1);
            if (i != this.getLesFigs().size() -1) {
                res = res +"\n";
            }
        }
        return res;
    }

    @Override
    public void dessine(Graphics2D g, AffineTransform curTrans) {
        for(int i = 0 ; i < this.nbrFigs() ; i ++) {
            this.getLesFigs().get(i).dessine(g, curTrans);
        }
    }

    /**
     * @return the lesFigs
     */
    public ArrayList<Figure> getLesFigs() {
        return lesFigs;
    }
}
